#pragma once
#include <functional>
#include<iostream>
#include<string>
#include"Log.hpp"
#include<queue>
#include<vector>
#include<memory>

#include"Mutex.hpp"
#include"Thread.hpp"
#include"Cond.hpp"

namespace ThreadPoolModule
{
    using namespace ThreadModule;
    using namespace LogModule;
    using namespace MutexModule;
    using namespace CondModule;
    using thread_t = std::shared_ptr<Thread>;

    //测试方法
    void DTest()
    {
        while(true)
        {
            LOG(LogLevel::DEBUG) << "i am a test way!";
            sleep(1);
        }
    }

    //默认创建线程池的数量
    const static int defaultnum = 5;

    template<class T>
    class ThreadPool
    {
    private:
        bool IsEmpty(){return _taskq.empty();}
        //处理任务
        void HanderTask(std::string name)
        {
            LOG(LogLevel::INFO) << "Thread coming in HanderTask" << "[" << name << "]";
            while(true)
            {
                //1.拿任务
                T t;
                {
                    LockGuard lockguard(_mutex);
                    while(IsEmpty() && _isrunning)
                    {
                        //没任务就去休眠
                        _wait_num++;
                        _cond.Wait(_mutex);
                        _wait_num--;
                    }
                    // 2. 任务队列为空 && 线程池退出了(不再入任务)
                    if(IsEmpty() && !_isrunning)
                        break;

                    t = _taskq.front();
                    _taskq.pop();
                }
                //2.处理任务
                t(name);//规定所有的任务必须提供各自的处理方法且不带参
            }
            

        }
    public:
        ThreadPool(int num = defaultnum):_num(num),_wait_num(0),_isrunning(false)
        {
            for(int i = 0; i < num ;i++)
            {
                //创建线程对象
                _threads.push_back(std::make_shared<Thread>(std::bind(&ThreadPool::HanderTask,this,std::placeholders::_1)));
                LOG(LogLevel::INFO) << "Creat thread" <<_threads.back()->GetName() << "sucess";
            }
        }
        void Start()
        {
            if(_isrunning) return;//防止重复启动
            _isrunning = true;
            for(auto &thread_ptr :_threads)
            {
                thread_ptr->Start();
                LOG(LogLevel::INFO) << "Start thread" <<thread_ptr->GetName() << "对象...sucess";
            }
        }

        void Wait()
        {
            for(auto &thread_ptr :_threads)
            {
                thread_ptr->Join();
                LOG(LogLevel::INFO) << "Join thread" <<_threads.back()->GetName() << "对象...sucess";
            }
        }


        ////函数指针（或函数名）可以隐式转换成 std::function<...> 对象，但只能产生一个“临时量”
        //把 const std::function<...> 放进了 std::queue，而 std::queue 的底层容器 std::deque 要求元素类型必须是「非 const、非 volatile」的。
        //所以直接传临时拷贝T in
        void Equeue(T in)
        {
            LockGuard lockguard(_mutex);
            //将任务转移到队列中外部不用，节省拷贝
            if(!_isrunning) return;
            _taskq.push(std::move(in));
            if(_wait_num > 0)
            {
                _cond.Notify();
            }
        }

        void Stop()
        {
            //停止条件
            LockGuard lockguard(_mutex);
            if(_isrunning)
            {
            //3.不能再入任务了
                _isrunning = false;
            //1.线程自己退出
            //2.历史任务被处理完
                if(_wait_num > 0)
                {
                    _cond.NotifyAll();
                }
            }
        }

        ~ThreadPool()
        {

        }
    private:
        int _num;                       //threadsnum
        std::vector<thread_t> _threads; //organize threads
        std::queue<T> _taskq;           //task queue
        int _wait_num;                  //waiting number
        Mutex _mutex;                   //protect lock
        Cond  _cond;                    //waiting conditions
        bool _isrunning;                //thread State
    };
}